#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    setWindowFlag(Qt::Tool);
     setWindowFlag(Qt::WindowStaysOnTopHint);
     HWND hWnd = (HWND)winId();
     LONG style = GetWindowLong(hWnd, GWL_EXSTYLE);
     SetWindowLong(hWnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE);

     initKeyMappingWin();

     for (const auto& item : keyMapping)
     {
         connect(item.uiCtl, &QPushButton::clicked, this, &Widget::buttonClicked);
     }

}
void Widget::initKeyMappingWin()
{
    keyMapping.append({ ui->pb0, '0', '0', 0, 1, u8"0", u8")" });
    keyMapping.append({ ui->pb1, '1', '1', 0, 1, u8"1", u8"!" });
    keyMapping.append({ ui->pb2, '2', '2', 0, 1, u8"2", u8"@" });
    keyMapping.append({ ui->pb3, '3', '3', 0, 1, u8"3", u8"#" });
    keyMapping.append({ ui->pb4, '4', '4', 0, 1, u8"4", u8"$" });
    keyMapping.append({ ui->pb5, '5', '5', 0, 1, u8"5", u8"%" });
    keyMapping.append({ ui->pb6, '6', '6', 0, 1, u8"6", u8"^" });
    keyMapping.append({ ui->pb7, '7', '7', 0, 1, u8"7", u8"&&" });
    keyMapping.append({ ui->pb8, '8', '8', 0, 1, u8"8", u8"*" });
    keyMapping.append({ ui->pb9, '9', '9', 0, 1, u8"9", u8"(" });
    keyMapping.append({ ui->pba, 'A', 'A', 1, 1, u8"a", u8"A" });
    keyMapping.append({ ui->pbb, 'B', 'B', 1, 1, u8"b", u8"B" });
    keyMapping.append({ ui->pbc, 'C', 'C', 1, 1, u8"c", u8"C" });
    keyMapping.append({ ui->pbd, 'D', 'D', 1, 1, u8"d", u8"D" });
    keyMapping.append({ ui->pbe, 'E', 'E', 1, 1, u8"e", u8"E" });
    keyMapping.append({ ui->pbf, 'F', 'F', 1, 1, u8"f", u8"F" });
    keyMapping.append({ ui->pbg, 'G', 'G', 1, 1, u8"g", u8"G" });
    keyMapping.append({ ui->pbh, 'H', 'H', 1, 1, u8"h", u8"H" });
    keyMapping.append({ ui->pbi, 'I', 'I', 1, 1, u8"i", u8"I" });
    keyMapping.append({ ui->pbj, 'J', 'J', 1, 1, u8"j", u8"J" });
    keyMapping.append({ ui->pbk, 'K', 'K', 1, 1, u8"k", u8"K" });
    keyMapping.append({ ui->pbl, 'L', 'L', 1, 1, u8"l", u8"L" });
    keyMapping.append({ ui->pbm, 'M', 'M', 1, 1, u8"m", u8"M" });
    keyMapping.append({ ui->pbn, 'N', 'N', 1, 1, u8"n", u8"N" });
    keyMapping.append({ ui->pbo, 'O', 'O', 1, 1, u8"o", u8"O" });
    keyMapping.append({ ui->pbp, 'P', 'P', 1, 1, u8"p", u8"P" });
    keyMapping.append({ ui->pbq, 'Q', 'Q', 1, 1, u8"q", u8"Q" });
    keyMapping.append({ ui->pbr, 'R', 'R', 1, 1, u8"r", u8"R" });
    keyMapping.append({ ui->pbs, 'S', 'S', 1, 1, u8"s", u8"S" });
    keyMapping.append({ ui->pbt, 'T', 'T', 1, 1, u8"t", u8"T" });
    keyMapping.append({ ui->pbu, 'U', 'U', 1, 1, u8"u", u8"U" });
    keyMapping.append({ ui->pbv, 'V', 'V', 1, 1, u8"v", u8"V" });
    keyMapping.append({ ui->pbw, 'W', 'W', 1, 1, u8"w", u8"W" });
    keyMapping.append({ ui->pbx, 'X', 'X', 1, 1, u8"x", u8"X" });
    keyMapping.append({ ui->pby, 'Y', 'Y', 1, 1, u8"y", u8"Y" });
    keyMapping.append({ ui->pbz, 'Z', 'Z', 1, 1, u8"z", u8"Z" });
    keyMapping.append({ ui->pbSpace, VK_SPACE, VK_SPACE, 0, 0, u8" ", u8" " });
    keyMapping.append({ ui->pbComma, VK_OEM_COMMA, VK_OEM_COMMA, 0, 1, u8",", u8"<" });
    keyMapping.append({ ui->pbDot, VK_OEM_PERIOD, VK_OEM_PERIOD, 0, 1, u8".", u8">" });
    keyMapping.append({ ui->pbTab, VK_TAB, VK_TAB, 0, 0, u8"", u8"" });
    keyMapping.append({ ui->pbCaps, VK_CAPITAL, VK_CAPITAL, 0, 0, u8"", u8"" });
    keyMapping.append({ ui->pbShift, VK_SHIFT, VK_SHIFT, 0, 0, u8"", u8"" });
    keyMapping.append({ ui->pbBackspace, VK_BACK, VK_BACK, 0, 0, u8"", u8"" });
    keyMapping.append({ ui->pbEnter, VK_RETURN, VK_RETURN, 0, 0, u8"", u8"" });
}

void Widget::switchCases()
{
    bool mixedCaps = (shift ^ capslock);
    for (const auto& item : keyMapping)
    {
        if (item.capsSwitch && !item.shiftSwitch)
        {
            item.uiCtl->setText(capslock ? item.upperCase : item.lowCase);
        }
        if (item.shiftSwitch && !item.capsSwitch)
        {
            item.uiCtl->setText(shift ? item.upperCase : item.lowCase);
        }
        if (item.shiftSwitch && item.capsSwitch)
        {
            item.uiCtl->setText(mixedCaps ? item.upperCase : item.lowCase);
        }
    }
}

HWND Widget::findFocusWindow()
{
    GUITHREADINFO gui = { 0 };
    gui.cbSize = sizeof(GUITHREADINFO);
    GetGUIThreadInfo(0, &gui);
    return gui.hwndFocus;
}
void Widget::sendKeyEvent(HWND hWnd, QObject* button)
{
    auto found = std::find_if(keyMapping.begin(), keyMapping.end(),
        [button](const KeyMap& m) { return m.uiCtl == button; });
    if (found != keyMapping.end())
    {
        if (shift)
        {
            INPUT inputs[4];
            ZeroMemory(inputs, sizeof(inputs));
            inputs[0].type = INPUT_KEYBOARD;
            inputs[0].ki.wVk = VK_SHIFT;
            inputs[1].type = INPUT_KEYBOARD;
            inputs[1].ki.wVk = found->qtEnum1;
            inputs[2].type = INPUT_KEYBOARD;
            inputs[2].ki.wVk = found->qtEnum1;
            inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
            inputs[3].type = INPUT_KEYBOARD;
            inputs[3].ki.wVk = VK_SHIFT;
            inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;
            SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
        }
        else
        {
            INPUT inputs[2];
            ZeroMemory(inputs, sizeof(inputs));
            inputs[0].type = INPUT_KEYBOARD;
            inputs[0].ki.wVk = found->qtEnum1;
            inputs[1].type = INPUT_KEYBOARD;
            inputs[1].ki.wVk = found->qtEnum1;
            inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
            SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
        }
    }
}

void Widget::buttonClicked()
{
    QObject* src = sender();
    if (src == ui->pbShift)
    {
        shift = !shift;
        switchCases();
        if (shift)
        {
            /* 手动松开Shift不返回，继续执行发送Shift点击消息 */
            /* 按Shift键可以改变中英文输入 */
            return;
        }
    }
    else if (src == ui->pbCaps)
    {
        capslock = !capslock;
        switchCases();
    }
    HWND hWnd = findFocusWindow();
    sendKeyEvent(hWnd, src);
    if (shift)
    {
        ui->pbShift->setChecked(false);
        shift = false;
        switchCases();
    }
}
Widget::~Widget()
{
    delete ui;
}

